package cn.mw.cmdb.processor;

import cn.hutool.core.bean.BeanDesc;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.bean.PropDesc;
import cn.hutool.core.bean.copier.CopyOptions;
import cn.mw.cmdb.anno.CMDBHeader;
import cn.mw.cmdb.entity.*;
import cn.mw.cmdb.param.InstanceSearchParam;
import cn.mw.cmdb.param.TableSearchParam;
import cn.mw.cmdb.service.impl.CmdbServiceManage;
import cn.mw.cmdb.service.impl.InstanceServiceImpl;
import cn.mw.cmdb.service.impl.ModelPropertyServiceImpl;
import cn.mw.cmdb.util.CMDBTool;
import cn.mw.cmdb.viewProcessor.RelateDataViewProcessor;
import cn.mw.cmdb.viewProcessor.ViewProcessorManage;
import cn.mw.components.mongodb.entity.CriteriaOpsType;
import cn.mw.components.mongodb.entity.SubCondition;
import cn.mw.microMonitorCommon.api.common.Constants;
import cn.mw.microMonitorCommon.entity.cmdb.RelatedDataType;
import cn.mw.microMonitorCommon.entity.cmdb.TableHeaderItem;
import com.google.common.base.Strings;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.StringUtils;

import java.lang.reflect.Field;
import java.util.*;
import java.util.stream.Collectors;

import static cn.mw.microMonitorCommon.entity.cmdb.TableHeaderItem.flexNum;

/**
 * 模型通用字段Processor
 */
@Slf4j
public class StaticsProcessorCommonInstance implements TableDataProccessor {

    private CmdbServiceManage cmdbServiceManage;

    private TableSearchParam tableDataParam;

    private InstanceSearchParam instanceSearchParam;

    public StaticsProcessorCommonInstance(CmdbServiceManage cmdbServiceManage, TableSearchParam tableDataParam,
                                          InstanceSearchParam instanceSearchParam) {
        this.cmdbServiceManage = cmdbServiceManage;
        this.tableDataParam = tableDataParam;
        this.instanceSearchParam = instanceSearchParam;

    }

    @Override
    public List genData(TableDataProcessorContext context) throws Exception {
        InstanceServiceImpl instanceService = (InstanceServiceImpl) cmdbServiceManage.getModelService(InstanceServiceImpl.ID);
        List<InstanceInfoExtend> instanceInfos = new ArrayList<>();
        String[] assetStateQuery = null;
        // 自定义分类场景，状态节点 id由上级id+资产状态组成 id由属性名:属性值拼接而成
        if (!Strings.isNullOrEmpty(tableDataParam.getId()) && tableDataParam.getId().contains(Constants.ID_SPLIT)) {
            assetStateQuery = tableDataParam.getId().split(Constants.ID_SPLIT)[1].split(Constants.PROPERTY_SPLIT);
            tableDataParam.setId(tableDataParam.getId().split(Constants.ID_SPLIT)[0]);
        }
        if (null == instanceSearchParam) {
            instanceSearchParam = new InstanceSearchParam();
            if (!Strings.isNullOrEmpty(tableDataParam.getId())) {
                SubCondition subCondition = new SubCondition(CriteriaOpsType.is.name(), tableDataParam.getId());
                instanceSearchParam.addSubCondition(CMDBTool.getFieldName(InstanceInfo::getModelId), subCondition);
            }
        }
        if (assetStateQuery != null) {
            Map<String, Object> searchData = new HashMap<>();
            if (assetStateQuery.length > 1) {
                searchData.put(assetStateQuery[0], assetStateQuery[1]);
            } else {
                searchData.put(assetStateQuery[0], null);
            }
            instanceSearchParam.setData(searchData);
        }
        //忽略null值注入
        BeanUtil.copyProperties(tableDataParam, instanceSearchParam, CopyOptions.create().setIgnoreNullValue(true));
        if(tableDataParam.isEnableMonitorStatus()){
            //查询资产状态
            instanceSearchParam.setEnableMonitorStatus(true);
        }
        //不分页查询,为了排序
        //instanceSearchParam.setPage(null);
        instanceInfos = instanceService.aggregateList(instanceSearchParam);
        List<Map> ret = new ArrayList<>();
        ViewProcessorManage processorManage = new ViewProcessorManage();

        List<TableHeaderItem> tableHeaderItems = context.getTableHeaderItems();
        if (null != instanceInfos && null != tableHeaderItems) {
            Set<RelateDataViewProcessor> relateDataViewProcess = processorManage.buildRelateDataViewProcessor(tableHeaderItems);
            Map<? extends Class<? extends RelateDataViewProcessor>, List<RelateDataViewProcessor>> collect = relateDataViewProcess.stream().collect(Collectors.groupingBy(s -> s.getClass()));
            Set<RelateDataViewProcessor> relateDataViewProcessors = new HashSet<>();
            collect.forEach((k,v)->{
                if(v!=null && v.size()>0){
                    RelateDataViewProcessor relateDataViewProcessor = v.get(0);
                    relateDataViewProcessors.add(relateDataViewProcessor);
                }
            });
            //初始化
            int seq = 0;
            for (InstanceInfoExtend instanceInfo : instanceInfos) {
                seq++;
                Map data = new LinkedHashMap();
                if (tableDataParam.isShowAllField()) {
                    Map<String, Object> dataMap = instanceInfo.getData();
                    data.putAll(dataMap);
                }
                for (TableHeaderItem item : tableHeaderItems) {
                    Object value = instanceInfo.getValue(item.getField());
                    data.put(item.getField(), value);
                }
                data.put(CMDBTool.getFieldName(InstanceInfoExtend::getModelName),instanceInfo.getModelName());
                data.put(CMDBTool.getFieldName(InstanceInfoExtend::getModelGroupName), instanceInfo.getModelGroupName());
                data.put(CMDBTool.getFieldName(InstanceInfoExtend::getModelId), instanceInfo.getModelId());
                data.put(CMDBTool.getFieldName(InstanceInfoExtend::getFinanceParentId), instanceInfo.getFinanceParentId());
                data.put(CMDBTool.getFieldName(InstanceInfoExtend::getGroupId), instanceInfo.getGroupId());ret.add(data);
                //data.put(SEQ, seq);

                if (null == relateDataViewProcessors || relateDataViewProcessors.size() == 0) {
                    continue;
                }
                for (RelateDataViewProcessor processor : relateDataViewProcessors) {
                    processor.init(instanceInfo, data);
                }
            }

            if (null == relateDataViewProcessors || relateDataViewProcessors.size() == 0) {
                return ret;
            }
            //查询外部服务关联数据
            for (RelateDataViewProcessor processor : relateDataViewProcessors) {
                processor.selectRelateData(context);
            }

            //设置关联数据
            for (Map s : ret) {
                for (RelateDataViewProcessor processor : relateDataViewProcessors) {
                    processor.setRelateData(s);
                }
            }
        }
        return ret;
    }

    @Override
    public List<TableHeaderItem> genDefaultTableHeader(Class clazz) throws Exception {
        long time1 = System.currentTimeMillis();
        ModelPropertyServiceImpl modelService = (ModelPropertyServiceImpl) cmdbServiceManage.getModelService(ModelPropertyServiceImpl.ID);
        List<PropertyInfo> commonModelPropertyInfos = modelService.getCommonModelPropertyInfos();
        Map<String, PropertyInfo> propertyIdByDtoMap = commonModelPropertyInfos.stream().collect(Collectors.toMap(s -> s.getId(), s -> s, (
                value1, value2) -> {
            return value2;
        }));
        long time2 = System.currentTimeMillis();
        BeanDesc desc = BeanUtil.getBeanDesc(clazz);
        Iterator<PropDesc> ite = desc.getProps().iterator();
        List<TableHeaderItem> tableHeaderItems = new ArrayList<>();
        while (ite.hasNext()) {
            PropDesc propDesc = ite.next();
            Field field = propDesc.getField();
            CMDBHeader annotation = field.getAnnotation(CMDBHeader.class);
            if (null != annotation) {
                TableHeaderItem item = new TableHeaderItem();
                if (propertyIdByDtoMap != null && propertyIdByDtoMap.containsKey(field.getName())) {
                    PropertyInfo propertyInfo = propertyIdByDtoMap.get(field.getName());
                    item.setHeaderName(propertyInfo.getName());
                    ForeignKey foreignKey = propertyInfo.getForeignKey();
                    if (null == foreignKey || !StringUtils.hasText(foreignKey.getKeyName())) {
                        item = new TableHeaderItem();
                    } else {
                        RelatedDataType relatedDataType = RelatedDataType.valueOf(foreignKey.getRelatedDataType());
                        item = TableHeaderItemExt.build().keyName(foreignKey.getKeyName());
                        item.setParseType(relatedDataType);
                    }
                    item.setField(propertyInfo.getId());
                    //list列表展示
                    boolean isShow = propertyInfo.getFieldViewAuthTypes() != null ? propertyInfo.getFieldViewAuthTypes().contains(FieldViewAuthType.list) : false;
                    item.setVisible(isShow);
                    item.setPropertyTypeId(propertyInfo.getPropertyTypeRef().getTypeId());
                } else {
                    item.setField(field.getName());
                    item.setHeaderName(annotation.name());
                    item.setVisible(annotation.visible());
                }

                item.setFlex(flexNum);
                item.setParseType(annotation.relateDataProcesor());
                item.setPropertyTypeId(annotation.propertyTypeId());
                tableHeaderItems.add(item);
            }
        }
        long time3 = System.currentTimeMillis();
        log.info("ProcessorCommonInstance::getCommonModelPropertyInfo耗时:" + (time2 - time1) + "ms;TableHeaderItem：" + (time3 - time2) + "ms");
        return tableHeaderItems;
    }

    private List<TableHeaderItem> getDefaultTableHeaderItem(Class clazz) {
        BeanDesc desc = BeanUtil.getBeanDesc(clazz);
        Iterator<PropDesc> ite = desc.getProps().iterator();
        List<TableHeaderItem> tableHeaderItems = new ArrayList<>();
        while (ite.hasNext()) {
            PropDesc propDesc = ite.next();
            Field field = propDesc.getField();
            CMDBHeader annotation = field.getAnnotation(CMDBHeader.class);
            if (null != annotation) {
                TableHeaderItem item = new TableHeaderItem();
                item.setField(field.getName());
                item.setHeaderName(annotation.name());
                item.setVisible(annotation.visible());
                item.setFlex(annotation.flex());
                item.setParseType(annotation.relateDataProcesor());
                tableHeaderItems.add(item);
            }
        }
        return tableHeaderItems;
    }
}
